home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / gopher+1.2b4 / object / GDgopherdir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-15  |  9.0 KB  |  472 lines

  1. /********************************************************************
  2.  * lindner
  3.  * 3.5
  4.  * 1993/04/15 21:35:12
  5.  * /home/mudhoney/GopherSrc/CVS/gopher+/object/GDgopherdir.c,v
  6.  * Exp
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: GDgopherdir.c
  14.  * Implement gopher directory routines
  15.  *********************************************************************
  16.  * Revision History:
  17.  * GDgopherdir.c,v
  18.  * Revision 3.5  1993/04/15  21:35:12  lindner
  19.  * Debug code, better .Link processing, better GDfromNet()
  20.  *
  21.  * Revision 3.4  1993/03/26  19:50:44  lindner
  22.  * Mitra fixes for better/clearer fromNet code
  23.  *
  24.  * Revision 3.3  1993/03/24  17:04:49  lindner
  25.  * bad strcmp() can check unmalloced() mem, fixed
  26.  *
  27.  * Revision 3.2  1993/03/18  22:13:29  lindner
  28.  * filtering, compression fixes
  29.  *
  30.  * Revision 3.1  1993/02/11  18:03:01  lindner
  31.  * Initial revision
  32.  *
  33.  * Revision 2.1  1993/02/09  22:46:50  lindner
  34.  * Many additions for gopher+
  35.  *
  36.  * Revision 1.4  1993/01/31  00:22:51  lindner
  37.  * Changed GDaddGS to merge entries with the same path.
  38.  * Added GDplusfromNet() to siphon data from network.
  39.  * GDfromLink now knows about ~/ inside of Path=
  40.  * Changed GDSearch to ignore leading character.
  41.  *
  42.  * Revision 1.3  1992/12/19  04:44:09  lindner
  43.  * Added GDplustoNet()
  44.  *
  45.  * Revision 1.2  1992/12/16  20:37:04  lindner
  46.  * Added function GDsearch(), does a linear search of a gopher directory
  47.  *
  48.  * Revision 1.1  1992/12/10  23:27:52  lindner
  49.  * gopher 1.1 release
  50.  *
  51.  *
  52.  *********************************************************************/
  53.  
  54.  
  55. #include "GDgopherdir.h"
  56. #include "Malloc.h"
  57.  
  58.  
  59. #include <string.h>
  60. #include <stdio.h>
  61. extern int DEBUG;
  62.  
  63.  
  64. /***********************************************************************
  65. ** Stuff for GopherDirObjs
  66. **
  67. ***********************************************************************/
  68.  
  69.  
  70. GopherDirObj*
  71. GDnew(size)
  72.   int size;
  73. {
  74.      int i;
  75.      GopherDirObj *temp;
  76.      
  77.      temp = (GopherDirObj*) malloc(sizeof(GopherDirObj));
  78.  
  79.      temp->Gophers = DAnew(size, GSnew, GSinit, GSdestroy, GScpy);
  80.  
  81.      temp->Title = STRnew();
  82.      temp->currentitem = 1;
  83.  
  84.      GDinit(temp);
  85.      return(temp);
  86. }
  87.  
  88.  
  89. void
  90. GDdestroy(gd)
  91.   GopherDirObj *gd;
  92. {
  93.      int i;
  94.  
  95.      DAdestroy(gd->Gophers);
  96.      
  97.      STRdestroy(gd->Title);
  98.      free(gd);
  99. }
  100.  
  101.  
  102. void
  103. GDinit(gd)
  104.   GopherDirObj *gd;
  105. {
  106.      int i;
  107.  
  108.      DAinit(gd->Gophers);
  109.      STRinit(gd->Title);
  110. }
  111.  
  112.  
  113. extern int DEBUG;
  114.  
  115. /** This proc adds a GopherObj to a gopherdir.
  116.     It will attempt to merge two items if need be..
  117.  **/
  118. void
  119. GDaddGSmerge(gd, gs)
  120.   GopherDirObj *gd;
  121.   GopherObj *gs;
  122. {
  123.     int num;
  124.  
  125.     num = GDSearch(gd, GSgetPath(gs));
  126.  
  127.     if (num == -1)
  128.          DApush(gd->Gophers, gs);
  129.      else {
  130.          GSmerge(GDgetEntry(gd, num),gs);
  131.     }
  132. }
  133.  
  134.  
  135. /*
  136.  * This one never tries to merge 
  137.  */
  138.  
  139. void
  140. GDaddGS(gd, gs)
  141.   GopherDirObj *gd;
  142.   GopherObj *gs;
  143. {
  144.     int num;
  145.  
  146.     if (GSgetType(gs) != 'X')
  147.          DApush(gd->Gophers, gs);
  148. }
  149.  
  150.  
  151. /*
  152.  * Really weird!!!  We need this for qsort,  don't know why we can't use
  153.  * GScmp...
  154.  */
  155.  
  156. int
  157. GSqsortcmp(gs1, gs2)
  158.   GopherObj **gs1, **gs2;
  159. {
  160.      if (GSgetTitle(*gs1) == NULL)
  161.       return(1);
  162.      if (GSgetTitle(*gs2) == NULL)
  163.       return(-1);
  164.      
  165.      /** No numbering set on either entry, or both numbered
  166.          entries have the same number   **/
  167.  
  168.      if (GSgetNum(*gs1) == GSgetNum(*gs2))
  169.       return(strcmp(GSgetTitle(*gs1), GSgetTitle(*gs2)));
  170.  
  171.      /** first one numbered, second not **/
  172.      if (GSgetNum(*gs1) != -1 && GSgetNum(*gs2) == -1)
  173.       return(-1);
  174.  
  175.      /** second one numbered, first not **/
  176.      if (GSgetNum(*gs1) == -1 && GSgetNum(*gs2) != -1)
  177.       return(1);
  178.  
  179.      /** Both numbered, integer compare them **/
  180.  
  181.      return(GSgetNum(*gs1) - GSgetNum(*gs2));
  182. }
  183.  
  184. /*
  185.  * Sorts a gopher directory
  186.  */
  187.  
  188. void
  189. GDsort(gd)
  190.   GopherDirObj *gd;
  191. {
  192.  
  193.      DAsort(gd->Gophers, GSqsortcmp);
  194. }
  195.  
  196.  
  197. void
  198. GDtoNet(gd, sockfd)
  199.   GopherDirObj *gd;
  200.   int sockfd;
  201. {
  202.      int i;
  203.      if (DEBUG) fprintf (stderr, "GDplustoNet\n");
  204.      for (i=0; i< GDgetNumitems(gd); i++) {
  205.       GStoNet(GDgetEntry(gd, i), sockfd);
  206.      }      
  207.  
  208. }
  209.  
  210.  
  211. void
  212. GDplustoNet(gd, sockfd, filter)
  213.   GopherDirObj *gd;
  214.   int          sockfd;
  215.   char         **filter;
  216. {
  217.      int i;
  218.  
  219.      for (i=0; i< GDgetNumitems(gd); i++) {
  220.       GSplustoNet(GDgetEntry(gd, i), sockfd,filter);
  221.      }      
  222. }
  223.  
  224. void
  225. GDtoNetHTML(gd, sockfd)
  226.   GopherDirObj *gd;
  227.   int sockfd;
  228. {
  229.      int i;
  230.      
  231.      writestring(sockfd, "<MENU>\r\n");
  232.      
  233.      for (i=0; i< GDgetNumitems(gd); i++) {
  234.       writestring(sockfd, "<LI>");
  235.       GStoNetHTML(GDgetEntry(gd, i), sockfd);
  236.      }      
  237.      writestring(sockfd, "</MENU>");
  238. }
  239.  
  240. /*
  241.  * Gopher+ counterpart to GDfromNet()
  242.  */
  243.  
  244.  
  245. #define DODEBUG(loc) if (DEBUG) { fprintf(stderr,"GDplusfromNet:%s;\n",loc);}
  246.  
  247. int
  248. GDplusfromNet(gd, fd, eachitem)
  249.   GopherDirObj *gd;
  250.   int fd;
  251.   int (*eachitem)();
  252. {
  253.      static GopherObj *TempGopher;
  254.      static char ZesTmp[1024];
  255.      int j, result;
  256.      char inputline[256];
  257.  
  258.      DODEBUG("start")
  259.      if (TempGopher == NULL)
  260.       TempGopher = GSnew();
  261.  
  262.      /** State: _begin_ **/
  263.  
  264.      result = readrecvbuf(fd, inputline, 1);
  265.      if (result <=0 || *inputline != '+') 
  266.       return(0);
  267.  
  268.      DODEBUG("after readrecvbuf")
  269.      /** State _FirstPlus_ **/
  270.  
  271.      result = readtotoken(fd, inputline, sizeof(inputline), ':');
  272.      if (result <=0)
  273.       return(result);
  274.  
  275.      DODEBUG("after readtotoken")
  276.      if (strcmp(inputline, "INFO")!=0) {
  277.       return(0);
  278.      }
  279.      DODEBUG("after INFO")
  280.      /** Read the space **/
  281.      readrecvbuf(fd, inputline, 1);
  282.  
  283.  
  284.      /*** State _FirstINFO_ ***/
  285.  
  286.      for (j=0; ; j++) {
  287.  
  288.            DODEBUG("for start")
  289.       ZesTmp[0] = '\0';
  290.       
  291.       GSinit(TempGopher);
  292.       result = GSplusfromNet(TempGopher, fd);
  293.       
  294.       switch (result) {
  295.       case MORECOMING:
  296.            GDaddGS(gd, TempGopher);
  297.            if (eachitem != NULL) 
  298.             eachitem();
  299.            break;
  300.  
  301.       case FOUNDEOF:
  302.            GDaddGS(gd, TempGopher);
  303.            return(j+1);
  304.  
  305.       case HARDERROR:  /** Give up reading - bad read or protocol error **/
  306.            return(j);
  307.  
  308.       case SOFTERROR:  /** This one was bad, but we can try for next **/
  309.            j= j-1;
  310.            if (j<0) j=0;
  311.            break;
  312.       }
  313.            
  314.      } /* for */
  315.  
  316.      /** Never get here **/
  317.  
  318. /*
  319.  * Fill up a GopherDirObj with GopherObjs, given a gopher directory coming
  320.  * from sockfd.
  321.  *
  322.  * For each GopherObj retrieved, eachitem() is executed.
  323.  *
  324.  */
  325.  
  326. void
  327. GDfromNet(gd, sockfd, eachitem)
  328.   GopherDirObj *gd;
  329.   int sockfd;
  330.   int (*eachitem)();
  331. {
  332.      static GopherObj *TempGopher;
  333.      static char ZesTmp[1024];
  334.      int i;
  335.  
  336.      if (DEBUG) fprintf(stderr, "GDfromNet...");
  337.      if (TempGopher == NULL)
  338.       TempGopher = GSnew();
  339.  
  340.      for (; ;) {
  341.  
  342.       ZesTmp[0] = '\0';
  343.       
  344.       GSinit(TempGopher);
  345.       i = GSfromNet(TempGopher, sockfd);
  346.       
  347.          /* In gopher+1.2b2 this routine clears up if GSfromNet returns 
  348.             a failure, better to clear up in GSfromNet so that the 
  349.             system returns in a known state - note that other callers of 
  350.             GSfromNet didn't clean up and crashed! */
  351.       
  352.       switch (i) {
  353.  
  354.       case 0:
  355.            GDaddGS(gd, TempGopher);
  356.            if (eachitem != NULL) eachitem();
  357.            break;
  358.  
  359.       case 1:  /* . on a line by itself, nothing more */
  360.            return;
  361.  
  362.       case SOFTERROR:  /** Unknown object type **/
  363.            break;
  364.  
  365.       case HARDERROR:
  366.            return;
  367.       }
  368.      }
  369.  
  370.  
  371. /*
  372.  * Given an open file descriptor and an inited GopherDirobj,
  373.  *   read in gopher links, and add them to a gopherdir
  374.  */
  375.  
  376. void
  377. GDfromLink(gd, fd, host, port, directory)
  378.   GopherDirObj *gd;
  379.   int          fd;
  380.   char         *host;
  381.   int          port;
  382.   char         *directory;
  383. {
  384.      GopherObj *gs;
  385.      char      testline[512];
  386.      int       num;
  387.      int result;
  388.  
  389.      gs = GSnew();
  390.  
  391.  
  392.      while (1) {
  393.       result = GSfromLink(gs, fd, host, port,directory);
  394.  
  395.       if (result == HARDERROR)
  396.            break;
  397.       if (result == SOFTERROR)
  398.            continue;
  399.  
  400.       if (*GSgetPath(gs) == '.')
  401.            GDaddGSmerge(gd, gs);
  402.       else
  403.            GDaddGS(gd, gs);
  404.  
  405.       if (result == FOUNDEOF)
  406.            break;
  407.  
  408.       GSinit(gs);
  409.      }
  410.       
  411.      GSdestroy(gs);
  412. }
  413.  
  414.  
  415. void
  416. GDtoLink(gd, fd)
  417.   GopherDirObj *gd;
  418.   int fd;
  419. {
  420.      int i;
  421.  
  422.      for (i=0; i< GDgetNumitems(gd); i++) {
  423.       GStoLink(GDgetEntry(gd, i), fd);
  424.      }      
  425.  
  426. }
  427.  
  428. /***  Search for a specific gopher item ***/
  429. /* Allow text to end in .Z - gd will never have a .Z item in it due to fix 
  430.    in gopherd/gopherd */
  431. int
  432. GDSearch(gd, text)
  433.   GopherDirObj *gd;
  434.   char         *text;
  435. {
  436.      int i;
  437.      int WasCtrlZ = 0;
  438.      GopherObj *gs;
  439.      int len;
  440.  
  441.      if (gd == NULL)
  442.       return(-1);
  443.  
  444.      if (text == NULL)
  445.       return(-1);
  446.  
  447.      len = strlen(text);
  448.      if (len >2) {
  449.       WasCtrlZ = (strcmp(text+strlen(text)-2,".Z")  == 0);
  450.       if (WasCtrlZ) 
  451.            text[strlen(text)-2] = '\0';
  452.      }
  453.     
  454.      for (i=0; i< GDgetNumitems(gd); i++) {
  455.       gs = GDgetEntry(gd, i);
  456.  
  457.       if (len >1 && strcmp(text+1, GSgetPath(gs)+1) == 0) {
  458.            if (WasCtrlZ) 
  459.             text[strlen(text)-2] = '.';
  460.         if (DEBUG) fprintf (stderr, "Matched\n");
  461.            return(i);
  462.       }
  463.      }
  464.      if (WasCtrlZ) 
  465.     text[strlen(text)-2] = '.';
  466.      if (DEBUG) fprintf (stderr, "No Match\n");
  467.      return(-1);
  468. }
  469.  
  470.